const CDP = require('chrome-remote-interface');

class CDPClient {
  constructor(host, port, options = {}) {
    this.host = host;
    this.port = port;
    this.client = null;
    this.connected = false;
    this.messageHandlers = [];
    this.errorHandlers = [];
    this.maxRetries = options.maxRetries || 3;
    this.retryDelay = options.retryDelay || 1000;
    this.onRetry = options.onRetry;
  }

  async connect() {
    let retries = 0;
    console.log('[Debug] Attempting to establish CDP connection...');
    while (retries < this.maxRetries) {
      try {
        await this._attemptConnection();
        return;
      } catch (err) {
        retries++;
        if (this.onRetry) {
          this.onRetry(retries, this.maxRetries);
        }
        if (retries === this.maxRetries) {
          const error = new Error(`Connection failed (${retries} attempts): ${err.message}\nPossible reasons:\n1. Debug target not started\n2. Debug port not enabled\n3. Incorrect host or port configuration`);
          this._notifyError(error);
          throw error;
        }
        console.log(`[Debug] Connection attempt ${retries}/${this.maxRetries} failed, waiting ${this.retryDelay}ms before retry...`);
        await new Promise(resolve => setTimeout(resolve, this.retryDelay));
      }
    }
  }

  async _attemptConnection() {
    try {
      console.log(`[Debug] Attempting to connect to ${this.host}:${this.port}...`);
      this.client = await CDP({
        host: this.host,
        port: this.port,
        local: true
      });

      console.log('[Debug] CDP connection established successfully');
      this.connected = true;

      // Enable Console and Runtime domains
      await this.client.Runtime.enable();
      // await this.client.Console.enable();
      console.log('[Debug] Enabled Runtime and Console domains');

      // Set up event listeners
      this.client.on('Console.messageAdded', (params) => {
        console.log('[Debug] Console message:', params.message);
        this.messageHandlers.forEach(handler => handler(params.message));
      });

      this.client.on('Runtime.consoleAPICalled', (params) => {
        // console.log('[Debug] Runtime console API called:', params);
        this.messageHandlers.forEach(handler => handler(params));
      });

      // this.client.on('event', (message) => {
      //   console.log('[Debug] Received CDP event:', message.method);
      //   // console.log('[Debug] CDP event details:', JSON.stringify(message, null, 2));
      //   this.messageHandlers.forEach(handler => handler(message));
      // });

      this.client.on('disconnect', () => {
        console.log('[Debug] CDP connection disconnected');
        if (this.connected) {
          this.connected = false;
          const error = new Error('CDP connection lost, will automatically reconnect when target is detected');
          this._notifyError(error);
        }
      });
    } catch (error) {
      console.error('[Debug] Connection attempt failed:', error.message);
      this._notifyError(error);
      throw error;
    }
  }

  onMessage(handler) {
    this.messageHandlers.push(handler);
    console.log('[Debug] New message handler registered');
  }

  onError(handler) {
    this.errorHandlers.push(handler);
    console.log('[Debug] New error handler registered');
  }

  _notifyError(error) {
    console.error('[Debug] Error occurred:', error.message);
    this.errorHandlers.forEach(handler => handler(error));
  }

  async send(method, params = {}) {
    if (!this.connected || !this.client) {
      const error = new Error('Not connected to debug target');
      this._notifyError(error);
      throw error;
    }

    try {
      console.log(`[Debug] Sending CDP command: ${method}`);
      const result = await this.client.send(method, params);
      console.log(`[Debug] CDP command ${method} completed successfully`);
      return result;
    } catch (error) {
      console.error(`[Debug] CDP command ${method} failed:`, error.message);
      this._notifyError(error);
      throw error;
    }
  }

  disconnect() {
    if (this.client) {
      console.log('[Debug] Initiating CDP connection disconnect');
      this.client.close();
      this.client = null;
      this.connected = false;
      console.log('[Debug] CDP connection closed successfully');
    }
  }
}

module.exports = CDPClient;